package repository

import (
	"booksmart/book/internal/domain"
	"booksmart/book/internal/repository/cache"
	"booksmart/book/internal/repository/dao"
	"context"
	"database/sql"
	"time"
)

var (
	ErrUserDuplicateEmail = dao.ErrUserDuplicate
	ErrUserNotFind        = dao.ErrUserNotFind
)

type UserRepository struct {
	dao   *dao.UserDao
	cache *cache.UserCache
}

func NewUserRepository(dao *dao.UserDao, cache *cache.UserCache) *UserRepository {
	return &UserRepository{dao: dao,
		cache: cache}
}

func (repo *UserRepository) Create(ctx context.Context, u domain.User) error {
	return repo.dao.Insert(ctx, repo.domainToEntity(u))
}

func (repo *UserRepository) FindByEmail(ctx context.Context, email string) (domain.User, error) {
	u, err := repo.dao.FindByEmail(ctx, email)
	if err != nil {
		return domain.User{}, err
	}
	return repo.entityToDomain(u), nil

}

func (repo *UserRepository) FindById(ctx context.Context, id int64) (domain.User, error) {
	u, err := repo.cache.Get(ctx, id)
	if err == nil {
		return u, err
	}
	//if errors.Is(err, cache.ErrKeyNotExits) {
	//
	//}
	//采用 redis没数据，或redis错误，都加载缓存
	ue, err := repo.dao.FindById(ctx, id)
	if err != nil {
		return domain.User{}, err
	}
	u = repo.entityToDomain(ue)
	go func() {
		err = repo.cache.Set(ctx, u)
		if err != nil {
			//打印日志，不需要返回错误
		}
	}()
	return u, nil
}

func (repo *UserRepository) FindByPhone(ctx context.Context, phone string) (domain.User, error) {
	u, err := repo.dao.FindByPhone(ctx, phone)
	if err != nil {
		return domain.User{}, err
	}
	return repo.entityToDomain(u), err
}

func (repo *UserRepository) entityToDomain(ud dao.Users) domain.User {
	return domain.User{
		Id:       ud.Id,
		Email:    ud.Email.String,
		Password: ud.Password,
		Phone:    ud.Phone.String,
		Ctime:    time.UnixMilli(ud.Ctime),
	}
}

func (repo *UserRepository) domainToEntity(ud domain.User) dao.Users {
	return dao.Users{
		Id: ud.Id,
		Email: sql.NullString{
			String: ud.Email,
			Valid:  ud.Email != "",
		},
		Phone: sql.NullString{
			String: ud.Phone,
			Valid:  ud.Phone != "",
		},
		Password: ud.Password,
		Ctime:    ud.Ctime.UnixMilli(),
	}
}

func (repo *UserRepository) FindByWechat(ctx context.Context, openID string) (domain.User, error) {
	u, err := repo.dao.FindByWechat(ctx, openID)
	if err != nil {
		return domain.User{}, err
	}
	return repo.entityToDomain(u), nil
}
